﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using BrasilFramework.Controle.WPF.Comum;
using BrasilFramework.Controle.WPF.Comum.Validacao;

namespace BrasilFramework.Controle.WPF
{
    public class Calendario : DatePicker
    {
        private readonly ValidatorManager _gerenciadorValidacao = new ValidatorManager();
        private readonly RegexValidator _validadorExpressao = new RegexValidator { IsShowIndicator = false };
        private readonly RequiredValidator _validadorObrigatoriedade = new RequiredValidator { IsShowIndicator = false };

        private DatePickerTextBox _campoTexto;

        public Calendario()
        {
            SelectedDateChanged += DateChanged;
            Unloaded += CustomDatePickerUnloaded;

        }

        private void DateChanged(object sender, SelectionChangedEventArgs e)
        {
            LimparMarcaDAgua();
        }

        private void CustomDatePickerUnloaded(object sender, RoutedEventArgs e)
        {
            SelectedDateChanged -= DateChanged;
        }

        protected override void OnInitialized(EventArgs e)
        {
            base.OnInitialized(e);
            _validadorObrigatoriedade.SetManagerAndControl(_gerenciadorValidacao, this);
            _validadorExpressao.SetManagerAndControl(_gerenciadorValidacao, this);
            RegistrarValidacao();
        }

        protected override void OnRender(System.Windows.Media.DrawingContext drawingContext)
        {
            base.OnRender(drawingContext);

            FieldInfo fiTextBox = typeof(DatePicker).GetField("_textBox", BindingFlags.Instance | BindingFlags.NonPublic);
            if (fiTextBox == null) return;

            _campoTexto = (DatePickerTextBox)fiTextBox.GetValue(this);
            _campoTexto.KeyDown += EventoTeclado.CampoApenasNumero;
            _campoTexto.KeyUp += FormatarData;
            _campoTexto.LostFocus += Validar;

            LimparMarcaDAgua();
        }

        private void LimparMarcaDAgua()
        {
            PropertyInfo propriedadeMarcaDAgua = typeof(DatePickerTextBox).GetProperty("Watermark", BindingFlags.Instance | BindingFlags.NonPublic);
            if (propriedadeMarcaDAgua == null) return;
            propriedadeMarcaDAgua.SetValue(_campoTexto, string.Empty, null);
        }

        private void RegistrarValidacao()
        {
            if (!IsInitialized) return;

            Text = string.Empty;

            _validadorObrigatoriedade.Finalizar();

            if (Obrigatorio)
            {
                _validadorObrigatoriedade.ErrorMessage = string.Format(Mensagem.CampoObrigatorio, NomeAmigavel);
                _validadorObrigatoriedade.Inicializar();
            }

            _validadorExpressao.Finalizar();

            _validadorExpressao.Expression = ExpressaoRegular.DATA;
            _validadorExpressao.ErrorMessage = string.Format(Mensagem.CampoInvalido, NomeAmigavel);
            _validadorExpressao.Inicializar();
        }

        private void Validar(object sender, RoutedEventArgs e)
        {
            var controleTexto = (DatePickerTextBox)sender;
            DateTime data;
            if (!DateTime.TryParse(controleTexto.Text, out data)) controleTexto.Text = string.Empty;
            LimparMarcaDAgua();
        }

        public List<string> Erros()
        {
            List<ValidatorBase> validacao = _gerenciadorValidacao.ValidateAll();
            return validacao.Select(item => item.ErrorMessage).ToList();
        }

        private void FormatarData(object sender, KeyEventArgs e)
        {
            var controleTexto = (DatePickerTextBox)sender;
            controleTexto.Text = EventoTeclado.Formatar(controleTexto.Text, "##/##/####");
            controleTexto.SelectionStart = controleTexto.Text.Length;
            LimparMarcaDAgua();
        }

        #region Propriedades

        public static readonly DependencyProperty PropriedadeObrigatorio =
            DependencyProperty.Register(
                "Obrigatorio",
                typeof(bool),
                typeof(Calendario),
                new PropertyMetadata(false, PropriedadeMudou));

        public static readonly DependencyProperty PropriedadeNomeAmigavel =
            DependencyProperty.Register(
                "NomeAmigavel",
                typeof(string),
                typeof(Calendario),
                new PropertyMetadata(string.Empty, PropriedadeMudou));

        [Description("Obriga o preenchimento do campo."), Category("Validação")]
        public bool Obrigatorio
        {
            get { return (bool)GetValue(PropriedadeObrigatorio); }
            set { SetValue(PropriedadeObrigatorio, value); }
        }

        [Description("Nome amigável para o controle. Este nome será exibido nas mensagens de validação."),
         Category("Validação")]
        public string NomeAmigavel
        {
            get { return (string)GetValue(PropriedadeNomeAmigavel); }
            set { SetValue(PropriedadeNomeAmigavel, value); }
        }

        private static void PropriedadeMudou(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            ((Calendario)sender).RegistrarValidacao();
        }

        #endregion
    }
}